//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package pxb.android.zipalign;

import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel.MapMode;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;

public class FastZipIn implements Closeable, Source {
    public static final long LOCSIG = 67324752L;
    public static final long CENSIG = 33639248L;
    public static final long ENDSIG = 101010256L;
    public static final int CENHDR = 46;
    public static final int ENDHDR = 22;
    static final int GPBF_ENCRYPTED_FLAG = 1;
    static final int GPBF_DATA_DESCRIPTOR_FLAG = 8;
    static final int GPBF_UTF8_FLAG = 2048;
    static final int GPBF_UNSUPPORTED_MASK = 1;
    private List<FastZipEntry> entries;
    final ByteBuffer raf;
    RandomAccessFile file;
    long centralDirOffset = -1L;

    public FastZipIn(File fd) throws IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile(fd, "r");
        this.file = randomAccessFile;
        this.raf = randomAccessFile.getChannel().map(MapMode.READ_ONLY, 0L, fd.length()).order(ByteOrder.LITTLE_ENDIAN);
        this.readCentralDir();
    }

    public ByteBuffer getUncompressed(FastZipEntry entry) throws IOException, DataFormatException {
        return FastZipOut.getContent(this, entry);
    }

    public ByteBuffer locateSigningBlock() throws IOException {
        ByteBuffer raf = this.raf;
        if (this.centralDirOffset - 24L > 0L) {
            raf.position((int)this.centralDirOffset - 24);
            long sizeOfBlock = raf.getLong();
            if (sizeOfBlock <= 0L) {
                return null;
            }

            byte[] magic = new byte[16];
            raf.get(magic);
            byte[] V2_MAGIC = "APK Sig Block 42".getBytes(StandardCharsets.UTF_8);
            if (Arrays.equals(V2_MAGIC, magic)) {
                long sizeOfSeq = sizeOfBlock - 24L;
                long startOfApkSigningBlock = this.centralDirOffset - sizeOfBlock - 8L;
                if (sizeOfSeq > 0L && startOfApkSigningBlock > 0L) {
                    raf.position((int)startOfApkSigningBlock);
                    return (ByteBuffer)raf.slice().order(ByteOrder.LITTLE_ENDIAN).limit((int)(sizeOfBlock + 8L));
                }
            }
        }

        return null;
    }

    public List<FastZipEntry> entries() {
        return this.entries;
    }

    public long getEntryDataStart(FastZipEntry entry) {
        int fileNameLength = this.raf.getShort((int)(entry.localHeaderRelOffset + 26L)) & '\uffff';
        int extraFieldLength = this.raf.getShort((int)(entry.localHeaderRelOffset + 28L)) & '\uffff';
        return entry.localHeaderRelOffset + 30L + (long)fileNameLength + (long)extraFieldLength;
    }

    public ByteBuffer getRaw(FastZipEntry entry) throws IOException {
        long entryDataStart = this.getEntryDataStart(entry);
        ByteBuffer is = (ByteBuffer)this.raf.duplicate().position((int)entryDataStart);
        return (ByteBuffer)is.slice().order(ByteOrder.LITTLE_ENDIAN).limit(entry.compressionMethod == 0 ? (int)entry.unCompressSize : (int)entry.compressedSize);
    }

    static void skip(ByteBuffer is, int i) {
        is.position(is.position() + i);
    }

    public void verifyCRC(FastZipEntry entry) throws DataFormatException, IOException {
        ByteBuffer raw = this.getRaw(entry);
        long crc32Value;
        if (entry.compressionMethod == 0) {
            crc32Value = FastZipOut.crc(raw);
        } else {
            ByteBuffer in = raw.slice();
            int bufSize = 4096;
            byte[] buffer = new byte[bufSize];
            byte[] bufferOut = new byte[bufSize];
            Inflater inf = new Inflater(true);
            CRC32 crc = new CRC32();
            int total = 0;

            label44:
            while(in.hasRemaining()) {
                int p = Math.min(bufSize, in.remaining());
                in.get(buffer, 0, p);
                inf.setInput(buffer, 0, p);

                while(true) {
                    int c = inf.inflate(bufferOut);
                    crc.update(bufferOut, 0, c);
                    if (c <= 0) {
                        if (inf.finished() || inf.needsDictionary()) {
                            break label44;
                        }

                        if (inf.needsInput() && !in.hasRemaining()) {
                            throw new EOFException("Unexpected end of ZLIB input stream");
                        }
                        break;
                    }

                    total += c;
                }
            }

            if ((long)total != entry.unCompressSize) {
                throw new IOException("Size mismatch on inflated file: " + total + " vs " + entry.unCompressSize);
            }

            crc32Value = crc.getValue();
        }

        if (crc32Value != entry.crc) {
            throw new IOException("crc mismatch on inflated file: " + crc32Value + " vs " + entry.crc);
        }
    }

    public int size() {
        return this.entries.size();
    }

    private void readCentralDir() throws IOException {
        ByteBuffer raf = this.raf;
        long scanOffset = (long)(raf.limit() - 22);
        if (scanOffset < 0L) {
            throw new ZipException("File too short to be a zip file: " + raf.limit());
        } else {
            long stopOffset = scanOffset - 65536L;
            if (stopOffset < 0L) {
                stopOffset = 0L;
            }

            do {
                raf.position((int)scanOffset);
                if ((long)raf.getInt() == 101010256L) {
                    int diskNumber = raf.getShort() & '\uffff';
                    int diskWithCentralDir = raf.getShort() & '\uffff';
                    int numEntries = raf.getShort() & '\uffff';
                    int totalNumEntries = raf.getShort() & '\uffff';
                    skip(raf, 4);
                    this.centralDirOffset = (long)raf.getInt() & 4294967295L;
                    int commentLength = raf.getShort() & '\uffff';
                    if (numEntries == totalNumEntries && diskNumber == 0 && diskWithCentralDir == 0) {
                        if (commentLength > 0) {
                            skip(raf, commentLength);
                        }

                        ByteBuffer buf = (ByteBuffer)raf.duplicate().order(ByteOrder.LITTLE_ENDIAN).position((int)this.centralDirOffset);
                        this.entries = new ArrayList(numEntries);

                        for(int i = 0; i < numEntries; ++i) {
                            FastZipEntry newEntry = new FastZipEntry(buf);
                            if (newEntry.localHeaderRelOffset < this.centralDirOffset) {
                                this.entries.add(newEntry);
                            }
                        }

                        return;
                    } else {
                        throw new ZipException("Spanned archives not supported");
                    }
                }

                --scanOffset;
            } while(scanOffset >= stopOffset);

            throw new ZipException("End Of Central Directory signature not found");
        }
    }

    public void close() throws IOException {
        if (this.file != null) {
            this.file.close();
        }

    }
}
